iT邦幫忙

0

使用rust來開發ARM嵌入式裝置

  • 分享至 

  • xImage
  •  

所需部分

  • 一塊支援的開發板
    • 本範例會以Blue Pill為例
      • MCU Part number: STM32F103C8T6
      • MCU Architecture: ARM Cotex M3(ARMv7e-m)
        • RAM: 20K
        • ROM: 64K
          圖片
      • 中國版和ST原裝的指令集架構版本可能有所不同,而導致無法進行刷寫
版本 指令集架構 tag id(SW-DP) tag id(JTAG)
Chinese ARM Cortex-M3 r2p0 0x2ba01477 0x0ba00477
ST ARM Cortex-M3 r1p1 0x1ba01477 0x3ba00477
  • 軟體環境
    • OpenOCD
    • GDB
      • gdb-multiarch
      • arm-none-eabi-gdb
    • Rust
      • 安裝相關工具
        $ rustup target add thumbv6m-none-eabi thumbv7m-none-eabi thumbv7em-none-eabi thumbv7em-none-eabihf
        $ rustup component add llvm-tools-preview
        $ cargo install cargo-binutils cargo-generate cargo-embed
      

建立專案

1 初始化

  1. 模板建立
    $ cargo generate --git https://github.com/rust-embedded/cortex-m-quickstart
    🤷   Project Name: f103c8t6_p1
    🔧   Destination: /home/user/文件/rust/f103c8t6_p1 ...
    🔧   project-name: f103c8t6_p1 ...
    🔧   Generating template ...
    🔧   Moving generated files into: `/home/user/文件/rust/f103c8t6_p1`...
    🔧   Initializing a fresh Git repository
    ✨   Done! New project created /home/user/文件/rust/f103c8t6_p1
    
  2. 建立完成到目錄
    $ cd f103c8t6_p1
    
  3. 加入一些必要功能
    • 安裝工具
      $ cargo add rtt-target critical-section defmt-rtt
      
    • 修改cargo.toml
         [dependencies]
         cortex-m = {version="*",features = ["critical-section-single-core"]} # Access to the generic ARM peripherals
      

2 硬體配置

  • MCU的指令集架構: .cargo/config
    [build]
    # Pick ONE of these default compilation targets
    # target = "thumbv6m-none-eabi"        # Cortex-M0 and Cortex-M0+
    target = "thumbv7m-none-eabi"          # Cortex-M3
    # target = "thumbv7em-none-eabi"       # Cortex-M4 and Cortex-M7 (no FPU)
    # target = "thumbv7em-none-eabihf"     # Cortex-M4F and Cortex-M7F (with FPU)
    # target = "thumbv8m.base-none-eabi"   # Cortex-M23
    # target = "thumbv8m.main-none-eabi"   # Cortex-M33 (no FPU)
    # target = "thumbv8m.main-none-eabihf" # Cortex-M33 (with FPU)
    
  • 記憶體大小&起始地址配置: memory.x
      MEMORY
      {
        /* NOTE 1 K = 1 KiBi = 1024 bytes */
        /* TODO Adjust these memory regions to match your device memory layout */
        /* These values correspond to the STM32F103C8T6, one of the few devices QEMU can emulate */
        FLASH : ORIGIN = 0x08000000, LENGTH = 64K
        RAM : ORIGIN = 0x20000000, LENGTH = 20K
      }
    
  • 函式庫管理: cargo.toml
[package]
authors = ["neko0xff <neko_0xff@protonmail.com>"]
edition = "2021"
readme = "README.md"
name = "f103c8t6_p1"
version = "0.1.0"

[dependencies]
cortex-m = {version="*",features = ["critical-section-single-core"]} # Access to the generic ARM peripherals
cortex-m-rt = "*"               # Startup code for the ARM Core
cortex-m-semihosting = "*"
embedded-hal = "*"              # Access to generic embedded functions (`set_high`)
panic-halt = "*"                # Panic handler
nb = "*"
debouncr = "*"
rtt-target = "*"
critical-section = "*"
defmt-rtt = "*"

[dependencies.stm32f1xx-hal]
version = "*"
features = ["rt", "stm32f103", "medium"]

# this lets you use `cargo fix`!
[[bin]]
name = "f103c8t6_p1"
test = false
bench = false

[profile.release]
codegen-units = 1 # better optimizations
debug = true # symbols are nice and they don't increase the size on Flash
lto = true # better optimizations

編寫程式

當所有環境和配置都完成後,就可開始撰寫主程式

  • 範例功能部分
    • 反覆點亮三顆LED
    • 使用UART1來不停傳送字元'S'&字串'Echo ...'
  • 貼士
    • 不使用
      • #![no_std]: Rust的標準函式庫
      • #![no_main]: Rust提供的main函式當進入點
    • 直接使用
      • #[entry]: 直接使用cortex-m-rt crate提供的函式當進入點
      • use panic_halt as _;: 提供了一個 panic_handler 定義程式的恐慌行為

主程式

  • '/src/main.rs'
#![deny(unsafe_code)]
#![no_std]
#![no_main]

use core::fmt::Write;
use panic_halt as _;
use nb::block;
use cortex_m::asm::nop;
use cortex_m_rt::entry;
use stm32f1xx_hal::{
    pac,
    prelude::*,
    timer::Timer,
    serial::{Config, Serial},
};
use rtt_target::{rprintln, rtt_init_print};


#[entry]
fn main() -> ! {
    // Get access to the core peripherals from the cortex-m crate
    let cp = cortex_m::Peripherals::take().unwrap();
    // Get access to the device specific peripherals from the peripheral access crate
    let dp = pac::Peripherals::take().unwrap();

    // Take ownership over the raw flash and rcc devices and convert them into the corresponding
    // HAL structs
    let mut flash = dp.FLASH.constrain();
    let rcc = dp.RCC.constrain();

    // Freeze the configuration of all the clocks in the system and store the frozen frequencies in `clocks`
    let clocks = rcc.cfgr.freeze(&mut flash.acr);
    // Configure the syst timer to trigger an update every second
    let mut timer = Timer::syst(cp.SYST, &clocks).counter_hz();
    timer.start(10.Hz()).unwrap();

    // Acquire the GPIOC peripheral
    let mut gpioa = dp.GPIOA.split();
    let mut gpioc = dp.GPIOC.split();
    let mut afio = dp.AFIO.constrain();
    
    // Configure gpio C pin 13 & 14 & 15 as a push-pull output.
    // The `crh` register is passed to the function in order to configure the port. 
    // For pins 0-7, crl should be passed instead.
    let mut led1 = gpioc.pc13.into_push_pull_output(&mut gpioc.crh);
    let mut led2 = gpioc.pc14.into_push_pull_output(&mut gpioc.crh);
    let mut led3 = gpioc.pc15.into_push_pull_output(&mut gpioc.crh);
    
    // USART1 on Pins A9 and A10
    let pin_tx1 = gpioa.pa9.into_alternate_push_pull(&mut gpioa.crh);
    let pin_rx1 = gpioa.pa10;
    // Create an interface struct for USART1 with 9600 Baud
    let serial1 = Serial::new(
        dp.USART1,
        (pin_tx1, pin_rx1),
        &mut afio.mapr,
        Config::default()
            .baudrate(9600.bps())
            .parity_none(),
        &clocks,
    );
    let (mut tx1, mut _rx1) = serial1.split(); // Separate into tx and rx channels
    
    rtt_init_print!();
    rprintln!("RTT Service is String....");
    tx1.write_str("\nUART1 is String....\n").unwrap();
    loop {
        block!(timer.wait()).unwrap();
        rprintln!("Echo ....");
        tx1.write_str("Echo ....\n").unwrap();
        for _ in 0..100_000 {
            nop();
        }
        led1.toggle();
        led2.toggle();
        led3.toggle();
        tx1.write(b'S').unwrap();
        tx1.write(b'\n').unwrap();
    }
}

編譯

當我們寫完功能需要進行除錯時,則需要進行編譯成該顆MCU支援的二進制檔案。

$ cargo build

則編譯完成的結果會直接輸出至f103c8t6_p2/target/thumbv7m-none-eabi/debug/

刷寫編譯完成的軔體

方案1: OpenOCD

  • 設置使用OpenOCD時刷寫的裝置類型: openocd.cfg
    source [find interface/stlink.cfg]  # 刷寫工具
    source [find target/stm32f1x.cfg]   # MCU型號
    
  • 開始刷寫
    $ openocd -s /usr/share/openocd/scripts -f openocd.cfg \
      -c "program target/thumbv7m-none-eabi/debug/f103c8t6_p1 verify reset exit"
    

方案2: cargo embed

  1. 手動刷寫: $ cargo embed --chip stm32f103c8
  2. 使用設置檔來刷寫
    • 新增Embed.toml
        [default.general]
        chip = "STM32F103C8"
      
        [default.rtt]
        enabled = true
      
        [default.gdb]
        enabled = false
      
    • 開始刷寫: $cargo embed

REF

中文

英文


圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
neiljiohu
iT邦新手 5 級 ‧ 2024-08-27 11:24:10

为了保障您的隐私和安全,我们采取了严格的保密措施,确保您的个人信息和订单细节得到最大程度的保护。我们明白作业代写对于您的学术生涯至关重要,因此我们努力提供可靠、高效的服务,让您从繁重的学业压力中解脱出来。

选择我们为您代写作业,意味着您选择了卓越、可靠和安全的学术支持。无论是研究作业、学士作业还是硕士博士作业,我们都有经验丰富的写手团队为您提供最优质的作业代写服务。让我们成为您学术成功路上的得力助手,放心交给我们,取得优异的成绩从容不迫。

我要留言

立即登入留言